import numpy as np
import theano

class WeightInit:
    def __init__(self, num_vis, num_hid, numpy_rng):
        self.__nv = num_vis
        self.__nh = num_hid
        self.__rng = numpy_rng
        
    def init(self):
        raise('Not specified error')
        pass

class SparseWeightInit(WeightInit):
    def __init__(self, num_vis, num_hid, numpy_rng, num_init=15, std=1):
        WeightInit.__init__(num_vis, num_hid, numpy_rng)
        self.__num_init = num_init
        self.__std = std

    def init(self):
        W = np.asarray(self.__rng.normal(size=(self.__nv, self.__nh)),
                      dtype=theano.config.floatX, scale=self.__std)
        for i in xrange(self.__nh):
            perm_idx = np.random.permutation(self.__nv)
            W[perm_idx[:self.__nv-self.__num_init+1],i] = 0
        
    return W

class UniformWeightInit(WeightInit):
    def __init__(self, num_vis, num_hid, numpy_rng):
        WeightInit.__init__(num_vis, num_hid, numpy_rng)
        
    def init(self):
        W = np.asarray(self.__rng.uniform(
            low=-numpy.sqrt(24. / (self.__nv + self.__nh)),
            high=numpy.sqrt(24. / (self.__nv + self.__nh)),
            size=(self.__nv, self.__nh)), dtype=theano.config.floatX)
        
        return W
    
class GaussianWeightInit(WeightInit):
    def __init__(self, num_vis, num_hid, numpy_rng, std=1):
        WeightInit.__init__(num_vis, num_hid, numpy_rng)
        self.__std = std
        
    def init(self):
        W = np.asarray( 
            self.__rng.normal(size=(self.__nv, self.__nh), scale=self.__std), 
            dtype=theano.config.floatX)
        
        return W
    
    